#include "text_video.h"
#include <string.h>
#include <cstdint.h>

vc_info *current_vc;
vc_info all_vcs[8];

int is_monochrome(){
	return 0;//(get_BDA()->video_flags & 1<<2) == 1<<2;
}

int get_page_length(){
	return 50 * (80) * 2;
}

volatile screen_character *get_text_video_memory(){
	return (volatile screen_character *)(is_monochrome() ? 0xB0000 : 0xB8000);
}

/**
 * Write character to text buffer and move cursor
*/
void ___putch(char c,vc_info *_vc){
	int offset = (_vc->cursor_x + (_vc->cursor_y * 80/*get_BDA()->columns_per_row*/))*2;	
	volatile screen_character *location;
	location = (screen_character *) ( ((int)_vc->video_buffer) + offset);
	location->attribute = _vc->attrib;
	location->character = c;
	_vc->cursor_x++;
	if (_vc->cursor_x >= 80){
		_vc->cursor_x = 0;
		_vc->cursor_y++;
	}		
}

void write_crtc_register(char id,char val){
	int base = is_monochrome() ? 0x3B4 : 0x3D4;
	outb(base + 0,id);
	outb(base + 1,val);
}

void handle_escape(char c)
{
	//TODO:Implement escapes
}
static void scroll(vc_info *con)
{
	unsigned short *fb_adr;
	unsigned blank, temp;
	if (current_vc->no_scroll)
		return;
	blank = 0x20 | ((unsigned)con->attrib << 8);
	fb_adr = (unsigned short *) con->video_buffer;
/* scroll up */
	if(con->cursor_y >= 50)
	{
		temp = con->cursor_y - 50 + 1;
		memcpy(fb_adr, fb_adr + temp * 80,
			(50 - temp) * 80 * 2);
/* blank the bottom line of the screen */
		memsetw(fb_adr + (50 - temp) * 80,
			blank, 80);
		con->cursor_y = 50 - 1;
	}
}
void move_cursor()
{
	int offset = (current_vc->cursor_x + (current_vc->cursor_y * 80/*get_BDA()->columns_per_row*/));
	write_crtc_register(0x0E,offset >> 8);
	write_crtc_register(0x0F,offset);
}

void switch_vc(int vc_id)
{
	short offset;
	current_vc = &all_vcs[vc_id];
	offset = current_vc->video_buffer - get_text_video_memory();
	write_crtc_register(0x0C,offset >> 8);
	write_crtc_register(0x0D,(char) offset & 0xFF);
}

void __putch(char c,vc_info *_vc)
{
	switch (_vc->escape){
		case 0:
			break;
		case 1:
			if (c == '['){
				_vc->escape = 2;
				return;
			} else
				_vc->escape = 0;
			break;
		case 2:
			handle_escape(c);
	}
	if (c == 0x1B)
		_vc->escape = 1;
	else if (c == '\b'){
		if (_vc->cursor_x > 0){
			_vc->cursor_x--;
			___putch(' ',_vc);
			_vc->cursor_x--;
		} else if (_vc->cursor_y > 0){
			_vc->cursor_x = 79;			
			_vc->cursor_y--;
			___putch(' ',_vc);
			_vc->cursor_x = 79;			
			_vc->cursor_y--;
		}
	} else if (c == '\t')
		_vc->cursor_x = (_vc->cursor_x + 8) % 8;
	else if (c == '\n'){
		_vc->cursor_x = 0;
		_vc->cursor_y = _vc->cursor_y + 1;
	} else if(c >= ' ')
		___putch(c,_vc);
	if (_vc->cursor_x >= 80){
		_vc->cursor_x = 0;
		_vc->cursor_y = _vc->cursor_y + 1;
	}		
	scroll(_vc);
	if (_vc == current_vc)
		move_cursor();
}

void clear_video(){
	unsigned short *fb_adr;
	unsigned blank;
	blank = 0x20 | ((unsigned)current_vc->attrib << 8);
	fb_adr = (unsigned short *) current_vc->video_buffer;
	memsetw(fb_adr,blank, 80*50);
}

void clear_line()
{
	unsigned short *fb_adr;
	unsigned blank;
	blank = 0x20 | ((unsigned)current_vc->attrib << 8);
	fb_adr = (unsigned short *) ( ((int) current_vc->video_buffer) + ( 80 * current_vc->cursor_y * 2 ) );
	memsetw(fb_adr,blank, 80);
}

void position(int x,int y,int move_cursor_)
{
	current_vc->cursor_x = x;
	current_vc->cursor_y = y;
	if (move_cursor_)
		move_cursor();
}

void dputch(char c){
	__putch(c,current_vc);
}
void vcputch(char c,int vc)
{
	__putch(c,&all_vcs[vc]);
}
void kputch(char c)
{
	__putch(c,&all_vcs[0]);
}
void kprint(char *str)
{
	int i = 0;
   	while (str[i])
   	{
       kputch(str[i++]);
   	}
}

void set_attrib(int foreground,int background)
{
	current_vc->attrib = ( char ) ( ( background << 4 ) | foreground );
}

void disable_scroll(int scroll){
	current_vc->no_scroll = scroll;
}

void init_video(){
	int vc_id;
	for (vc_id = 0;vc_id <= 8;vc_id++){
		all_vcs[vc_id].attrib = 0x07;
		all_vcs[vc_id].cursor_x = 0;
		all_vcs[vc_id].cursor_y = 0;		
		all_vcs[vc_id].no_scroll = 0;
		all_vcs[vc_id].page_id = vc_id;
		all_vcs[vc_id].escape = 0;
		all_vcs[vc_id].video_buffer = (screen_character *)( ((uint32_t)get_text_video_memory()) + get_page_length() * vc_id);
	}
	current_vc = &all_vcs[0];
}

